package de.tu_darmstadt.gdi1.xcom.controller.util;

import java.util.LinkedList;
import java.util.List;

import de.tu_darmstadt.gdi1.framework.utils.Point;
import de.tu_darmstadt.gdi1.xcom.controller.ai.XcomAIGame;
import de.tu_darmstadt.gdi1.xcom.model.XcomTeam;
import de.tu_darmstadt.gdi1.xcom.model.elements.Ammo;
import de.tu_darmstadt.gdi1.xcom.model.elements.DirectionEnum;
import de.tu_darmstadt.gdi1.xcom.model.elements.Door;
import de.tu_darmstadt.gdi1.xcom.model.elements.Floor;
import de.tu_darmstadt.gdi1.xcom.model.elements.GameElement;
import de.tu_darmstadt.gdi1.xcom.model.elements.Human;
import de.tu_darmstadt.gdi1.xcom.model.elements.Medikit;
import de.tu_darmstadt.gdi1.xcom.model.elements.Mob;
import de.tu_darmstadt.gdi1.xcom.model.elements.Monster;
import de.tu_darmstadt.gdi1.xcom.model.elements.Switch;
import de.tu_darmstadt.gdi1.xcom.model.elements.Wall;

public class XcomLevelParser {

	private String level;

	public XcomLevelParser(String level) {
		this.level = level;
	}

	public void setLevel(String level) {
		this.level = level;
	}

	public XcomAIGame parse() {
		return parseLevel(level);
	}
	
	private String loadMOBs(List<GameElement>[][] gameBoard,
			String level, List<Mob> team1, List<Mob> team2) {
		
		while(!level.startsWith("//{") && level.length() > 0) {
			int index = level.indexOf("\n");
			String s = level.substring(2, index);
			level = level.substring(index + 1);
			
			List<GameElement> elemList = new LinkedList<GameElement>();
			//Type;X;Y;Direction;HP;AP;MD;SD;M
			String[] mobData = s.split(";");
			Point mobPos = new Point(Integer.parseInt(mobData[1]), Integer.parseInt(mobData[2]));
			
			Mob temp;
			if(mobData[0].equals("@")){
				Human h = new Human(Integer.parseInt(mobData[1]), Integer.parseInt(mobData[2]), 
						DirectionEnum.getDirectionFromChar(mobData[3].charAt(0)), 
						Integer.parseInt(mobData[4]), Integer.parseInt(mobData[5]));
				
				h.setMeeleDamage(Integer.parseInt(mobData[6]));
				h.setWeaponDamage(Integer.parseInt(mobData[7]));
				h.setMunition(Integer.parseInt(mobData[8]));
				team1.add(h);
				temp = h;
			}
			else{
				Monster m = new Monster(Integer.parseInt(mobData[1]), Integer.parseInt(mobData[2]), 
						DirectionEnum.getDirectionFromChar(mobData[3].charAt(0)), 
						Integer.parseInt(mobData[4]), Integer.parseInt(mobData[5]));
				
				m.setMeeleDamage(Integer.parseInt(mobData[6]));
				team2.add(m);
				temp = m;
			}
			temp.resetPoints();
			elemList.add(new Floor());
			elemList.add(temp);
			gameBoard[mobPos.getX()][mobPos.getY()] = elemList;
		}
		return level;
	}

	
	private String loadDoors(List<GameElement>[][] gameField,
			String level) {
		while(!level.startsWith("//{") && level.length() > 0){
			int index = level.indexOf("\n");
			String s = level.substring(2, index);
			level = level.substring(index + 1);
			
			if(s.contains(";")){
				String[] data = s.split(";");
				if(data.length == 5){
					Point sPoint = new Point(Integer.parseInt(data[0]), Integer.parseInt(data[1]));
					Point dPoint = new Point(Integer.parseInt(data[2]), Integer.parseInt(data[3]));
					boolean locked = true;
					if(data[4].equals("o"))
						locked = false;
					Door door = new Door(locked);
					
					List<GameElement> temp = gameField[dPoint.getX()][dPoint.getY()];
					if(temp instanceof Door){
						door = (Door)temp;
						door.setState(locked);
					}
					
					Switch sw = new Switch(dPoint, locked);
					List<GameElement> switchList = new LinkedList<GameElement>();
					switchList.add(sw);
					gameField[sPoint.getX()][sPoint.getY()] = switchList;
					gameField[dPoint.getX()][dPoint.getY()].set(0, door);
				}
			}
		}
		return level;
	}

	private XcomAIGame parseLevel(String level) {
		List<String> gameFieldLines = new LinkedList<String>();
		
		int maxX = 0, maxY = 0;
		while(!level.startsWith("//")){
			int index = level.indexOf("\n");
			gameFieldLines.add(level.substring(0, index));
			level = level.substring(index + 1);
			if(index + 1 > maxX)
				maxX = index;
			maxY++;
		}
		
		List<GameElement>[][] gameField = (List<GameElement>[][])new List[maxX][maxY];
		for(int i = 0; i < maxX;i++){
			for(int j = 0;j < maxY;j++){
				gameField[i][j] = getBoardElementsFor(gameFieldLines.get(j).charAt(i));
			}
		}
		
		List<Mob> team1List = new LinkedList<Mob>();
		List<Mob> team2List = new LinkedList<Mob>();
		
		if(level.startsWith("//{mobs}")){
			level = loadMOBs(gameField, level.substring(9), team1List, team2List);
		}
		
		XcomTeam team1 = new XcomTeam();
		XcomTeam team2 = new XcomTeam();
		
		team1.setMobs(team1List);
		team2.setMobs(team2List);
		
		if(level.startsWith("//{doors}")){
			level = loadDoors(gameField, level.substring(10));
		}
		
		XcomAIGame result = new XcomAIGame(gameField);
		
		result.setTeam(team1, true);
		result.setTeam(team2, false);
		
		if(level.startsWith("//{gamedata}")){
			level = loadGameData(result, level.substring(13));
		}
		
		return result;
	}

	private String loadGameData(XcomAIGame gd, String level) {
		while(!level.startsWith("//{") && level.length() > 0){
			int index = level.indexOf("\n");
			String s = level.substring(2, index);
			level = level.substring(index + 1);
			
			if(s.contains("activeteam")){
				String[] temp = s.split(":");
				gd.setTeam1IsActive(temp[1].equals("@"));
			}
			if(s.contains("playedrounds")){
				String[] temp = s.split(":");
				gd.setPlayedRounds(Integer.parseInt(temp[1]));
			}
			if(s.contains("maxrounds")){
				String[] temp = s.split(":");
				gd.setMaxRounds(Integer.parseInt(temp[1]));
			}
			if(s.contains("teamZuseai")){
				String[] temp = s.split(":");
				int mode = Integer.parseInt(temp[1]);
				gd.setTeam2UseAi(mode);
			}

		}
		return level;
	}

	public List<GameElement> getBoardElementsFor(char c){

		List<GameElement> result = new LinkedList<GameElement>();

		switch (c) {
		case '#':
			result.add(new Wall());
			break;

		case '.':
			result.add(new Floor());
			break;

		case '@':
			result.add(new Floor());
			// human has 10 livepoints and 75 actionpoints at the beginning
			result.add(new Human(0, 0, DirectionEnum.North, 10, 75));
			break;

		case 'Z':
			result.add(new Floor());
			// an alien does have 1 livepoint and "unlimited" actionpoints
			result.add(new Monster(0, 0, DirectionEnum.North, 1, 99999));
			break;

		case 'c':
			result.add(new Switch(new Point(0, 0), true));
			break;

		case '=':
			result.add(new Door(true));
			break;

		case '+':
			result.add(new Floor());
			result.add(new Medikit());
			break;
		case 'm':
			result.add(new Floor());
			result.add(new Ammo());
			break;
		}
		return result;
	}

}
